iT邦幫忙

2023 iThome 鐵人賽

DAY 23
0

Day 23: 測試框架 - PyTest

學習原因:

接下來會學習從 0 到 1 建構自動化測試的流程:

https://ithelp.ithome.com.tw/upload/images/20230924/20162038iNrqUhF4MX.png

需要基於 測試框架 編寫各種的測試,提交程式碼以後,可以自動觸發整個測試腳本的運行,繼而生成報告以及發送通知執行結果。

測試框架提供了一個建立架構的規則和函式庫,我們需要學習應用,使能夠更有效地 編寫、組織和執行測試 。測試框架有非常多,我這裡會選用 PyTest 作介紹,讓你了解挑選測試框架的時候需要知道什麼。待你對自動化測試有更好的理解以後,可以根據專案的需求,選擇適合的測試框架。

學習目標:

  • 應用 PyTest 建立簡單的測試專案架構

PyTest

是一個基於 Python 的測試框架,需要在 Python 安裝 PyTest 套件

pip install pytest

建立第一個 test file

現在先來建立資料夾 /tests,然後再建一個 test_sample.py 測試 Module

# /tests/test_sample.py

def test_one():
	# Pytest 使用的是 Python 內建的 assert 函數,用來判斷結果是否符合預期。
	print("---test_one---")
	assert 1 + 1 == 2

def test_two():
	print("---test_two---")
	assert 2 + 2 == 4

執行的指令:

# Terminal

# 執行資料夾內所有的 test case
pytest tests

# 執行 test_sample.py 內所有的 test case
pytest tests/test_sample.py

執行結果都會是:

============================ test session starts ============================
platform darwin -- Python 3.9.6, pytest-7.4.0, pluggy-1.3.0
rootdir: /xxxxxxx/pytest_sample
collected 2 items                                                                                                                                                     

tests/test_sample.py ..                                              [100%]

============================= 2 passed in 0.02s =============================

還有一種常用的執行方法:

# -k 是用於選擇性運行指定測試用例的參數,可以指定匹配測試用例名稱的表達式
# 只執行符合表達式的 test case。

# 執行名稱含有 one 的 test case,所以只會執行 test_one()
pytest -k "one"

# 執行名稱含有 one 和 two 的 test case,所以沒有 test case 符合
pytest -k "one and two"

# 執行名稱含有 one 或 two 的 test case,所以 test_one() 和 test_two() 都會被執行
pytest -k "one or two"

執行的時候,有沒有發現為什麼都沒有看到 print() 的內容顯示?

執行 Pytest 時可以加入 -s 選項用於關閉 PyTest 默認的輸出捕獲。因為在默認情況下,PyTest 會捕獲並隱藏測試函數的標準輸出和標準錯誤輸出,以便在測試過程中更容易觀察測試結果。所以會看不到執行中的 output。因此加入 -s 就可以看到了。

執行 pytest -s 試試看,會發現 print() 的內容就會顯示了:

============================ test session starts ============================ 
platform darwin -- Python 3.9.6, pytest-7.4.0, pluggy-1.3.0
rootdir: /xxxxxxx/pytest_sample
collected 2 items                                                                                                                                                     

tests/test_sample.py ---test one---
.---test two---
.

============================  2 passed in 0.02s ============================ 

另外再介紹一個也很常用的 -v 選項,可以顯示更多詳細信息。默認情況下,PyTest 只顯示簡單的點 . 來表示每個測試用例的運行結果。

執行 pytest -v 試試看,會發現原本的 . 會變成 function 的名稱和測試結果:

============================ test session starts ============================ 
platform darwin -- Python 3.9.6, pytest-7.4.0, pluggy-1.3.0
rootdir: /xxxxxxx/pytest_sample
collected 2 items                                                                                                                                                     

tests/test_sample.py::test_one PASSED                                                                                                                           [ 50%]
tests/test_sample.py::test_two PASSED

============================  2 passed in 0.02s ============================ 

因此,一般想要顯示執行過程中的詳細資料和列印的內容,會在執行時同時加入 -s -v 的參數

PyTest 標準的測試搜索規則:

  1. 可在 Command line 指定 File Name / Directory。若沒有指定的話,則使用當前的 Directory,意即當前 Directory 下所有 Test Case 都會被執行。
  2. 找出測試 Module,是為 test_*.py*_test.py 命名的 Module
  3. 再找出 test_* 命名的 function 來執行。
  4. 或是找出 Test 開頭的 Class,在 Class 中找出 test_* 命名的 Method 來執行。

遵從以上規則命名測試 Module / Function / Class 和 Method 則可被 PyTest 視為 Test Cases。

pytest.ini 設定檔

pytest.ini 能改變 pytest 框架的執行規則。通過 pytest —help 可以查看 pytest.ini 中可以添加的參數與選項。

常用參數:

  • addopts: 設定 pytest 執行時所帶的參數,避免每次執行都需要手動輸入。

    就如上述提到的 -s -v 不想每次執行時都需要打這麼長的指令,可以寫加 pytest.ini

    # pytest.ini
    
    addopts = -s -v
    
  • testpaths: 設定 test case 的路徑,只會搜索指定路徑下的測試 Module 來執行。

    專案內或許會有多過一個存放 test case 的資料夾,這樣就可以指定執行哪些資料夾了。

    # pytest.ini
    
    addopts = -s -v
    testpaths = tests
    

    會在輸出看到指定的 testpaths

    ============================ test session starts ============================ 
    platform darwin -- Python 3.9.6, pytest-7.4.0, pluggy-1.3.0
    rootdir: /xxxxx/pytest_sample
    configfile: pytest.ini
    testpaths: tests
    collected 2 items                                                                                                                                                     
    
    tests_api/test_sample.py::test_one ---test one---
    PASSED
    tests_api/test_sample.py::test_two ---test two---
    PASSED
    
    ============================ 2 passed in 0.01s ============================ 
    
  • markers: 當使用 @pytest.marker 來標記用例,需要在 pytest.ini 中設置,否則會出現 Warning。Marker 主要用來把 Test Cases 分類,I.e. 可按種類 / Priority 等作分類。

    # pytest.ini
    
    marker = 
    	web
    	api
    	p0
    
    # test_markers.py
    import pytest
    
    @pytest.mark.web
    def test_one():
    	assert True
    
    @pytest.mark.api
    def test_two():
    	assert True
    
    @pytest.mark.p0
    def test_three():
    	assert True
    

    則可以在 Terminal 執行,應用參數 -m 帶入 marker,將會執行所有帶有該 marker 的 test cases。

    # 執行 @pytest.mark.web 的 test cases,則為 test_one()
    pytest -m "web" 
    
    # 執行 @pytest.mark.api 的 test cases,則為 test_two()
    pytest -m "api" 
    
    # 執行 @pytest.mark.p0 的 test cases,則為 test_three()
    pytest -m "po"  
    

專案的套件管理 requirements.txt

在一個專案我們會需要用到很多的套件,可以應用 requirements.txt 去記錄該專案會用到的套件以及相應的版本,方便應用專案的人可以一鍵安裝所需的套件,快速執行專案。

# requirements.txt
# <package>==<version>
pytest==7.4.0
selenium==4.10.0
# 安裝 requirements.txt 的套件指令
pip install -r requirements.txt

就這樣,PyTest 專案最基本的測試架構,就有以下內容了。

├── tests
      └── test_*.py
├── pytest.ini
└── requirement.txt

接下來會先把整個測試流程串起來,再來擴展 PyTest 的測試架構。

額外補充:

常聽到有 TDD 和 BDD 測試框架,我們先了解一下什麼是 TDD 和 BDD:

TDD (Test Driven Development) 測試驅動開發

  1. TDD 是一種開發方法,確保每個功能都有相關的測試用例,並且在修改現有程式碼時能夠快速發現問題,關注單元測試的設計
  2. 針對開發內容寫 Test Cases,先寫 Test Cases 再開發,開發人員按照「紅、綠、重構」的循環進行工作:先編寫會 失敗的測試 (紅),然後編寫足夠的代碼使其 通過 (綠),最後對程式碼進行 重構 以保持其清晰度和簡潔性。
  3. TDD 有助於確保每個功能都有相關的測試用例,並且在修改現有代碼時能夠快速發現問題。

BDD (Behavior Driven Development) 行為驅動開發

  1. BDD 是一種開發方法,強調軟體的行為和需求。
  2. BDD 通過更自然的語言(如 Gherkin)來描述軟體的行為,幫助各個領域的利益相關者更好地理解需求。
  3. BDD 的測試案例通常以「Given-When-Then」的結構描述:給定某種情境,當某種事件發生時,預期的結果應該是什麼。
  4. BDD 強調團隊合作和共享對需求的理解,以確保所有人對軟體的行為都有一致的理解。

會發現其實 TDD 和 BDD 在講的開發模式,而不是測試框架。只是我們在進行不同的開發模式時,可以選用支援的測試框架。像是做開發系統的時候,可以套用測試框架 (I.e. PyTest, Unitest 等) 進行 TDD。但不會說是 TDD 測試框架,像我們 SDET 做的測試並不是 TDD,就只是單純的測試。

BDD 測試框架 (I.e. Cucumber, PyTest-bdd, Behave, Robot Framework, etc.) 強調使用自然語言 (I.e. Gerhkin) 描述測試,它特別為 BDD 開發模式而設,所以會說是 BDD 測試框架。

本篇文章應用的是 PyTest ,並非 BDD Framework,個人認為需要多寫一層 Gherkin 語法的 Feature 檔,某程度上是提高了開發的技術門檻。語句設計其實是一門藝術,如何可帶參數又能組織清晰的測試用例,還要顧及其重用性。在協作的時候,難度再進一步提高,各人有不一致的語句特色,組起來不知道會變成怎樣的文章。
亦因本文主要想讓大家學習怎樣做自動化測試,就先跳過這一 Part 了,如果有興趣的話,可以考慮應用 PyTest-bdd 套件作自學。


上一篇
Day 22: Git 的基礎應用
下一篇
Day 24: Allure Report 和 Logging
系列文
從 0 開始培育成為自動化測試工程師的學習指南30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言